﻿/**
*    Copyright (C) 2008  Chase Kernan 
*    chase.kernan@gmail.com
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
* 
*/

package com.chasekernan.hxnova.core.fleets;

import com.chasekernan.hxnova.core.dataholders.Global;
import com.chasekernan.hxnova.core.dataholders.SalvageHolder;
import com.chasekernan.hxnova.core.minerals.MineralSet;
import com.chasekernan.hxnova.core.SpaceObject;
import com.chasekernan.hxnova.core.stars.Concentrations;
import com.chasekernan.hxnova.utils.Utils;
import com.chasekernan.hxnova.utils.Vector;

/**
    A set of minerals is left befind when a fleet is scrapped or destroyed.
    It decays over time though.
**/
class Salvage extends SpaceObject {
    
    
    /**
        Thre rate at which salvage decays.
        Ex: 0.10 -> each mineral type losing 10% each turn.
    **/
    public static var DECAY_RATE = 0.10;
    
    /**
        Each mineral type must decay by at least this much each turn.
    **/
    public static var MINIMUM_DECAY = 10;
    
    public var minerals : MineralSet;
    
    /**
        If location is not given, it defaults to (0, 0);
        If minerals are not given, then it defaults to an empty mineral set.
    **/
    public function new(?location : Vector, ?minerals : MineralSet) {
        super();
        this.location = if (location == null) new Vector(0, 0) else location;
        this.minerals = if (minerals == null) new MineralSet() else minerals;
    }
    
    /**
        Decays the minerals left in the salvage and will remove itself if the 
        mass gets too low.
    **/
    public function run() {
        for (minType in Concentrations.MINERAL_TYPES) {
            var current = minerals.getValue(minType);
            var decayed = Math.max(MINIMUM_DECAY, DECAY_RATE * current);
            minerals.setValue(minType, 
                              Std.int(Math.max(0, current - decayed)));
        }
        
        if (minerals.getMass() <= 3) {
            Global.salvage.removeParticle(this);
        }
    }
    
    public static var XML_TITLE = "salvage";
    
    /**
        Sample xml: 
        <salvage x="45.34" y="344.322">
            <mineral_set>
                <ironium value="45">
                <boranium value="23">
                <germanium value="0">
            </mineral_set>
        </salvage>
    **/
    public static function writeToXml(s : Salvage) : Xml {
        var xml = Xml.parse('<' + XML_TITLE + '></' + XML_TITLE + '>')
                .firstChild();
        
        if(s.location != null) {
            xml.set('x', Std.string(s.location.x));
            xml.set('y', Std.string(s.location.y));
        }
        
        if (s.id != null) xml.set('id', Std.string(s.id));
        
        xml.addChild(MineralSet.writeToXml(s.minerals));
        
        return xml;
    }
    
    public static function readFromXml(xml : Xml) : Salvage {
        try {
            var salvage = new Salvage();
            
            if (xml.exists('x')) {
                salvage.location = new Vector(Std.parseFloat(xml.get('x')),
                                          Std.parseFloat(xml.get('y')));
            }
            
            if (xml.exists('id')) salvage.id = Std.parseInt(xml.get('id'));
                                      
            salvage.minerals = MineralSet.readFromXml(
                    Utils.getXmlElement(xml, MineralSet.XML_TITLE));
                    
            return salvage;
        } catch (e : Dynamic) {
            throw "Error while reading from salvage xml file: " + e;
        }
    }
    
    public function clone() : Salvage {
        var s = new Salvage(location.clone(), minerals.clone());
        s.id = id;
        return s;
    }
}

#if unit
import haxe.unit.TestCase;

class SalvageTest extends haxe.unit.TestCase {
    
    public function testSalvageXml() {
        var s = new Salvage();
        
        s.id = 5;
        s.location = new Vector(5, 23);
        s.minerals.setValue(Concentrations.MINERAL_TYPES[0], 20);
        s.minerals.setValue(Concentrations.MINERAL_TYPES[1], 34);
        
        var copy = Salvage.readFromXml(Salvage.writeToXml(s));
        assertEquals(5, copy.id);
        assertTrue(s.location.equals(copy.location));
        assertTrue(s.minerals.isEqualTo(copy.minerals));
    }
}
#end